package com.holly.unit.deform;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.holly.unit.auth.api.context.LoginContext;
import com.holly.unit.auth.api.pojo.login.LoginUser;
import com.holly.unit.bpmn.api.WorkflowApi;
import com.holly.unit.core.constants.CommonConstant;
import com.holly.unit.core.pojo.response.ResponseData;
import com.holly.unit.core.pojo.response.SuccessResponseData;
import com.holly.unit.db.api.DbOperatorApi;
import com.holly.unit.db.api.constants.DataBaseConstants;
import com.holly.unit.deform.api.DeformEngineApi;
import com.holly.unit.deform.api.constants.DeformConstants;
import com.holly.unit.deform.api.exception.DeformException;
import com.holly.unit.deform.api.exception.enums.DeformExceptionEnum;
import com.holly.unit.deform.api.util.RestDesformUtil;
import com.holly.unit.deform.config.DeformConfig;
import com.holly.unit.deform.context.DeformContext;
import com.holly.unit.deform.entity.*;
import com.holly.unit.deform.service.*;
import com.holly.unit.deform.util.*;
import org.springframework.http.HttpMethod;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 类描述: 表单引擎服务操作类
 *
 * @author fxr
 * @version 1.0.0
 * @date 2022/4/12 9:12
 */
public class DeformEngineOperator implements DeformEngineApi<ModelAndView,DesignForm> {


    private DeformConfig config;

    public DeformEngineOperator(DeformConfig config) {
        this.config = config;
    }

    private DeformBaseInfoService deformBaseInfoService = DeformContext.deformBaseInfoService();

    private DeformDataService deformDataService = DeformContext.deformDataService();

    private DbOperatorApi dbOperatorApi = DeformContext.dbOperatorApi();

    private DeformTempletService deformTempletService = DeformContext.deformTempletService();

    private DeformUrlAuthService deformUrlAuthService = DeformContext.deformUrlAuthService();

    private DeformAuthService deformAuthService = DeformContext.deformAuthService();

    private DeformRouteService deformRouteService = DeformContext.deformRouteService();

    private WorkflowApi workflowApi = DeformContext.activitiOperator();

    @Override
    public ModelAndView queryFormViewData(DesignForm designForm, String dataId, String onlineDataId, ModelAndView modelAndView) {
        // 首先查询出表单配置json
        if (designForm == null) {
            throw new DeformException(DeformExceptionEnum.DEFORM_NO_EXIST_ERROR);
        }
        modelAndView.addObject("designForm", deformBaseInfoService.queryAllDictItem(designForm));

        // 再判断是否为新增
        if (!"add".equals(dataId)) {
            DesignFormData designFormData = null;
            //update-begin--Author:zhangdaihao  Date:20191003 for：实现表单的渲染，直接通过online dataid进行渲染，design_form_data无数据-------------------
            //1.判断表数据ID onlineDataId不为空，则优先走通过表获取逻辑
            if(StrUtil.isNotEmpty(onlineDataId)){
                String tbname = null;
                //通过online对应表查询数据库
                String desformDesignStr = designForm.getDesformDesignJson();
                if(StrUtil.isNotEmpty(desformDesignStr)){
                    JSONObject json = JSONObject.parseObject(desformDesignStr);
                    if(json.get("config")!=null){
                        JSONObject config = (JSONObject) json.get("config");
                        if(config.get("onlineForm")!=null){
                            tbname = (String) config.get("onlineForm");
                        }
                    }
                }
                if(StrUtil.isNotEmpty(tbname)){
                    Map<String,Object> dataMap = deformDataService.queryOneByTableNameAndId(tbname,onlineDataId);
                    if (dataMap == null) {
                        throw new DeformException(DeformExceptionEnum.DEFORM_NO_EXIST_ERROR);
                    }
                    designFormData = new DesignFormData();
                   /* String subTables = deformDataService.getSubTablesByTableName(tbname);
                    designFormData = new DesignFormData();
                    //判断是否主子表，是的话，把关联子表数据也查询出来
                    if(StrUtil.isNotEmpty(subTables)){
                        for(String sub:subTables.split(",")){
                            String deString = null;
                            try {
                                deString = URLEncoder.encode("[{}]", "UTF-8");
                            } catch (UnsupportedEncodingException e) {
                                e.printStackTrace();
                            }
                            dataMap.put("sub-table-design_"+sub,deString);
                        }
                    }*/

                    //此处判断如果是oracle数据库，则把map数据库key转成小写
                    try {
                        String dbType = dbOperatorApi.getDatabaseType();
                        if(DataBaseConstants.DB_TYPE_ORACLE.equalsIgnoreCase(dbType)){
                            designFormData.setDesformDataJson(JSONObject.toJSONString(FormDataUtil.transLowerCaseMapKey(dataMap)));
                        }else{
                            designFormData.setDesformDataJson(JSONObject.toJSONString(dataMap));
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        designFormData.setDesformDataJson(JSONObject.toJSONString(dataMap));
                    }
                    designFormData.setDesformId(designForm.getId());
                    designFormData.setDesformCode(designForm.getDesformCode());
                    designFormData.setDesformName(designForm.getDesformName());
                    designFormData.setOnlineFormCode(tbname);
                    designFormData.setOnlineFormDataId(onlineDataId);
                    designFormData.setId("ONLINE-DATA-TEMP-ID");
                }
            }else{
                //2.判断表数据库ID为空，则通过表单设计器data中获取数据
                designFormData = deformDataService.selectById(dataId);
            }
            //update-end--Author:zhangdaihao  Date:20191003 for：实现表单的渲染，直接通过online dataid进行渲染，design_form_data无数据-------------------
            /*if (designFormData == null) {
                throw new DeformException(DeformExceptionEnum.DEFORM_QUERY_BY_ID_ERROR,dataId);
            }*/
            modelAndView.addObject("designFormData", designFormData);
        }
        return modelAndView;
    }

    @Override
    public ModelAndView queryFormViewById(String desformId, String dataId, String onlineDataId, ModelAndView modelAndView) {
        // 首先查询出表单配置json
        DesignForm designForm = deformBaseInfoService.getById(desformId);
        return this.queryFormViewData(designForm, dataId,onlineDataId, modelAndView);
    }

    @Override
    public ModelAndView queryFormViewByCode(String desformCode, String dataId, String onlineDataId, ModelAndView modelAndView) {
        return this.queryFormViewByCode(desformCode, dataId, onlineDataId, false, modelAndView);
    }

    @Override
    public ModelAndView queryFormAutoViewByCode(String desformCode, String dataId, String onlineDataId, ModelAndView modelAndView) {
        // 查询出表单配置和所有的视图
        LambdaQueryWrapper<DesignForm> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DesignForm::getParentCode, desformCode);
        queryWrapper.eq(DesignForm::getIzMobileView, DeformConstants.IS_MOBILE_VIEW_Y);

        List<DesignForm> designFormList = deformBaseInfoService.list(queryWrapper);
        //移动视图模板
        DesignForm mobileForm = null;
        if (designFormList.size() > 0) {
            // 循环判断是否有移动端视图
            mobileForm = designFormList.get(0);
        } else {
            mobileForm = deformBaseInfoService.getByCode(desformCode);
        }
        if (mobileForm == null) {
            throw new DeformException(DeformExceptionEnum.DEFORM_NO_EXIST_ERROR);
        }
        return this.queryFormViewData(mobileForm, dataId, onlineDataId, modelAndView);
    }

    @Override
    public ModelAndView queryFormViewByCode(String desformCode, String dataId, String onlineDataId, boolean isExternal, ModelAndView modelAndView) {
        // 首先查询出表单配置json
        DesignForm designForm = deformBaseInfoService.getByCode(desformCode);
        if (designForm != null && isExternal) {
            JSONObject json = JSON.parseObject(designForm.getDesformDesignJson());
            JSONObject config = json.getJSONObject("config");
            boolean allowExternalLink = config.getBooleanValue("allowExternalLink");
            // 判断是否允许打开外部链接
            if (!allowExternalLink) {
                throw new DeformException(DeformExceptionEnum.DEFORM_ENGINE_LINK_DISABLE);
            }
        }
        return this.queryFormViewData(designForm, dataId,onlineDataId, modelAndView);
    }


    @Override
    public ModelAndView doIndex(ModelAndView modelAndView, HttpServletRequest request) {
        try {
            TokenUtil.verifyToken(request);

            modelAndView.addObject("baseURL", BaseUrlUtil.getBaseUrl(request));
            modelAndView.addObject("qiniuConfig", QiniuUtil.getConfig().toJSONString());
            modelAndView.addObject("themeColor", config.getDesformThemeColor());
            modelAndView.setViewName("desform/designForm");
        } catch (Exception e) {
            e.printStackTrace();
            modelAndView.addObject("message", e.getMessage());
            modelAndView.setViewName("desform/error");
        }
        return modelAndView;
    }

    @Override
    public ModelAndView desgForm(String id, Boolean isTemplet, ModelAndView modelAndView, HttpServletRequest request) {
        if (!StrUtil.isEmpty(id)) {

            // 模板表设计页面
            if (isTemplet != null && isTemplet) {
                DesignFormTemplet designFormTemplet = deformTempletService.getById(id);
                if (designFormTemplet != null) {
                    modelAndView.addObject("designJson", designFormTemplet.getTempletJson());
                }
            } else {
                DesignForm designForm = deformBaseInfoService.getById(id);
                if (designForm != null) {
                    modelAndView.addObject("desform", designForm);
                    modelAndView.addObject("desformName", designForm.getDesformName());
                    modelAndView.addObject("designJson", designForm.getDesformDesignJson());
                }
            }
        }
        return this.doIndex(modelAndView, request);
    }

    @Override
    public ModelAndView doFormView(ModelAndView modelAndView, String urlType, String desformCode, String dataId, String onlineDataId, HttpServletRequest request) {
        try {
            // 判断url是否有打开授权
            if (deformUrlAuthService.urlIsPassed(desformCode, urlType)) {
                modelAndView.addObject("action", urlType);
                modelAndView.addObject("themeColor", config.getDesformThemeColor());
                modelAndView.addObject("baseURL", BaseUrlUtil.getBaseUrl(request));
                modelAndView.addObject("qiniuConfig", QiniuUtil.getConfig().toJSONString());

                if (CommonConstant.DESIGN_FORM_URL_TYPE_VIEW.equals(urlType)) {
                    modelAndView = queryFormViewById(desformCode, dataId, onlineDataId, modelAndView);
                } else {
                    // 判断是否是从移动端发起的请求
                    boolean isMobile = BrowserUtil.isMobile(request);
                    // 如果是就判断是否配置了移动端视图，配置了就走移动端的视图，否则走默认视图
                    if (isMobile) {
                        modelAndView = queryFormAutoViewByCode(desformCode, dataId, onlineDataId, modelAndView);
                    } else {
                        modelAndView = queryFormViewByCode(desformCode, dataId, onlineDataId, modelAndView);
                    }
                }
                //判断是否表单数据提交
                if(StrUtil.isNotEmpty(request.getParameter("formData"))){
                    modelAndView.addObject("formDataType", "formData");
                }else {
                    modelAndView.addObject("formDataType", "");
                }
                //判断是否任务发起申请提交的数据
                String procDefId = request.getParameter("procDefId");
                String tableName = request.getParameter("tableName");
                String procDeTitle = request.getParameter("procDeTitle");
                if(StrUtil.isNotEmpty(procDefId) && StrUtil.isNotEmpty(tableName) && StrUtil.isNotEmpty(procDeTitle)){
                    Map<Object, Object> map = new HashMap<>();
                    map.put("procDefId",procDefId);
                    map.put("tableName",tableName);
                    map.put("procDeTitle",procDeTitle);
                    if(StrUtil.isNotEmpty(onlineDataId)){
                        map.put("tableId",onlineDataId);
                    }
                      //工作流字段权限
                    String nodeId = request.getParameter("nodeId");
                    String routeId = request.getParameter("routeId");
                    if(StrUtil.isNotEmpty(nodeId) && StrUtil.isNotEmpty(routeId)){
                        if(nodeId.equals("开始节点")){
                            Map<String, Object> maps = workflowApi.fetchStartEventNodeByProcessDefinitionId(procDefId);
                            nodeId = maps.get("id").toString();
                        }
                        //根据节点Id,流程Id,表单Id查询配置的菜单权限
                        Map<String, String> mapValue = workflowApi.fetchActColByTaskId(procDefId, nodeId,routeId);
                        if(mapValue.size() > 0){
                            //取出表单Json
                            Object designForm = modelAndView.getModel().get("designForm");
                            DesignForm data = JSONObject.parseObject(JSONObject.toJSONString(designForm), DesignForm.class);
                            JSONObject desformDesignJson =JSONObject.parseObject(data.getDesformDesignJson());
                            JSONArray dataList = desformDesignJson.getJSONArray("list");
                            getJsonValue(dataList,mapValue);
                            data.setDesformDesignJson(desformDesignJson.toJSONString());
                            modelAndView.addObject("designForm", data);

                        }
                    }
                    modelAndView.addObject("activitiData",JSONObject.toJSONString(map));
                }else {
                    modelAndView.addObject("activitiData","{}");
                }

                // 查询权限
                LoginUser loginUser = LoginContext.me().getLoginUser();

                JSONObject userInfo = deformAuthService.getUserInfoByUsername(loginUser.getAccount());
                modelAndView.addObject("authUserInfoJson", userInfo.toJSONString());

                String taskId = request.getParameter("taskId");
                List<DesignFormAuth> desformAuths;
                if (StrUtil.isEmpty(taskId)) {
                    desformAuths = deformAuthService.queryByCode(desformCode);
                } else {
                    desformAuths = deformAuthService.queryByTaskId(desformCode, taskId);
                }
                modelAndView.addObject("authInfoJson", JSON.toJSONString(desformAuths));

                // 查询出有效的下一步路由地址
                DesignFormRoute desformRoute = deformRouteService.getEffectiveRoute(desformCode);
                if (desformRoute != null) {
                    modelAndView.addObject("nextRouteConfig", JSON.toJSONString(desformRoute));
                }
                // 判断有没有携带 routeDataId，有就查询出数据并传递给前台
                String routeDataId = request.getParameter("routeDataId");
                if (StrUtil.isNotBlank(routeDataId)) {
                    DesignFormData routeData = deformDataService.getById(routeDataId);
                    if (routeData != null) {
                        modelAndView.addObject("routeData", routeData.getDesformDataJson());
                    }
                }

                // 最后返回 model and view
                modelAndView.setViewName("desform/formGenerate");
                return modelAndView;
            } else {
                modelAndView.addObject("message", "无打开此链接的权限");
            }
        } catch (Exception e) {
            modelAndView.addObject("message", e.getMessage());
        }
        modelAndView.setViewName("desform/error");
        return modelAndView;
    }

    private void getJsonValue(JSONArray dataList, Map<String, String> mapValue) {
        for(int i=0;i<dataList.size();i++) {
            JSONObject json = dataList.getJSONObject(i);
            if(json.getString("type").equals("grid")){
                json.getJSONArray("columns").forEach(gridList -> {
                    JSONArray list = ((JSONObject)gridList).getJSONArray("list");
                    if (list.size() > 0) {
                        this.getJsonValue(list,mapValue);
                    }
                });
            }else if(json.getString("type").equals("card")){
                JSONArray list = json.getJSONArray("list");
                if (list.size() > 0) {
                    this.getJsonValue(list,mapValue);
                }
            }else if(json.getString("type").equals("sub-table-design")){
                json.getJSONArray("columns").forEach(subList -> {
                    JSONArray listSub = ((JSONObject) subList).getJSONArray("list");
                    if (listSub.size() > 0) {
                       this.getJsonValue(listSub,mapValue);
                    }
                });
            }else {
                String model = json.getString("model");
                if(mapValue.containsKey(model)){
                    JSONObject options = json.getJSONObject("options");
                    if(mapValue.get(model).equals("1")){
                        options.put("disabled",true);
                    }else {
                        options.put("hidden",true);
                    }
                    json.put("options",options);
                }
            }
        }
    }

    @Override
    public ModelAndView formView(String desformId, String dataId, ModelAndView modelAndView, HttpServletRequest request) {
        String urlType = CommonConstant.DESIGN_FORM_URL_TYPE_VIEW;
        return this.doFormView(modelAndView, urlType, desformId, dataId,null, request);
    }

    @Override
    public ModelAndView addDesformData(String desformCode, ModelAndView modelAndView, HttpServletRequest request) {
        String urlType = CommonConstant.DESIGN_FORM_URL_TYPE_ADD;
        return this.doFormView(modelAndView, urlType, desformCode, "add",null, request);
    }

    @Override
    public ModelAndView formEditByCode(String desformCode, String dataId, ModelAndView modelAndView, HttpServletRequest request) {
        String urlType = CommonConstant.DESIGN_FORM_URL_TYPE_EDIT;
        return this.doFormView(modelAndView, urlType, desformCode, dataId,request.getParameter("tableId"), request);
    }

    @Override
    public ModelAndView formEditByCodeByOnline(String desformCode, String onlineDataId, ModelAndView modelAndView, HttpServletRequest request) {
        String urlType = CommonConstant.DESIGN_FORM_URL_TYPE_EDIT;
        return this.doFormView(modelAndView, urlType, desformCode, null,onlineDataId, request);
    }

    @Override
    public ModelAndView formDetail(String desformCode, String dataId, ModelAndView modelAndView, HttpServletRequest request) {
        // 浏览页面只读模式
        modelAndView.addObject("isReadOnly", true);
        String urlType = CommonConstant.DESIGN_FORM_URL_TYPE_DETAIL;
        return this.doFormView(modelAndView, urlType, desformCode, dataId,request.getParameter("tableId"), request);
    }

    @Override
    public ModelAndView formDetailByOnline(String desformCode, String onlineDataId, ModelAndView modelAndView, HttpServletRequest request) {
        // 浏览页面只读模式
        modelAndView.addObject("isReadOnly", true);
        String urlType = CommonConstant.DESIGN_FORM_URL_TYPE_DETAIL;
        return this.doFormView(modelAndView, urlType, desformCode, null,onlineDataId, request);
    }

    @Override
    public ResponseData customUrlTest(JSONObject json, HttpServletRequest request) {
        boolean isPost = HttpMethod.POST.matches(request.getMethod());
        // post 为新增，put为修改，这里只对新增数据做处理
        if (isPost) {
            // 从传递进来的 formData 里抽取三个字段
            JSONObject formData = json.getJSONObject("desformDataJson");
            JSONObject staff = new JSONObject();
            staff.put("name", formData.getString("name"));
            staff.put("sex", formData.getString("sex"));
            staff.put("age", formData.getString("age"));
            LoginUser sysUser = LoginContext.me().getLoginUser();
            return RestDesformUtil.addOne("extract_test_staff", staff, sysUser.getToken());
        } else {
            // 其他请求不做处理
            return new SuccessResponseData();
        }
    }
}
